﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Geometry
{
    public class Line : Geometry
    {
        /// <summary>
        /// Direction Vector of the Line
        /// Attention! The vector Starting Point could not be on the line
        /// This is only Directional Vector
        /// </summary>
        public Vector vec { get; private set; }
        /// <summary>
        /// The point on the line
        /// </summary>
        public Point line_point { get; private set; }
        /// <summary>
        /// The a parameter from the y=ax+b
        /// </summary>
        public double a { get; private set; }
        /// <summary>
        /// The b paramtere from the y=ax=b
        /// </summary>
        public double b { get; private set; }

        /// <summary>
        /// Default Constructor
        /// </summary>
        public Line()
        {
            vec = new Vector();
            line_point = new Point();
            a = 0;
            b = 0;
        }

        /// <summary>
        /// Starting the line from the point and the angle
        /// </summary>
        /// <param name="lx">The X Coordinate of the point</param>
        /// <param name="ly">The Y Coordinate of the point</param>
        /// <param name="langle">Angle from the X Axis</param>
        public Line(Point p, Angle an)
        {
            vec = new Vector(an);
            line_point = new Point(p);
            Calculab();
        }

        /// <summary>
        /// Copy constructor
        /// </summary>
        public Line(Line lline)
        {
            vec = new Vector(lline.vec);
            line_point = new Point(lline.line_point);
            a = lline.a;
            b = lline.b;
        }

        /// <summary>
        /// Line Constructor form the 2 points, The direction vector is set from ONE to TWO
        /// </summary>
        /// <param name="one">Start of the direction vector</param>
        /// <param name="two">End of the direction vector</param>
        public Line(Point one, Point two)
        {
            vec = new Vector(one, two);
            line_point = new Point(one);
            Calculab();
        }

        public Line(Point p, Vector v)
        {
            vec = new Vector(v);
            line_point = new Point(p);
            Calculab();
        }

        /// <summary>
        /// Check if the point is in line
        /// </summary>
        /// <param name="l">The line to be checked</param>
        /// <param name="p">The point to be checked</param>
        /// <returns>True if the point is in line</returns>
        public static bool IsInLine(Line l, Point p)
        {
            double check_y = l.a * p.x + l.b;
            if (Math.Round(check_y, 5) == Math.Round(p.y, 5)) return true;
            return false;
        }

        /// <summary>
        /// Get's the X coordinate of the point on the line from the Y coordinate
        /// </summary>
        /// <param name="y">The Y Coordinate</param>
        /// <returns>The X Coordinate</returns>
        public double GetXFromY(double y)
        {
            double x = (y - this.b) / this.a;
            return x;
        }

        /// <summary>
        /// Get's the Y coordinate of the point on the line from the X coordinate
        /// </summary>
        /// <param name="x">The X Coordinate</param>
        /// <returns>The Y Coordinate</returns>
        public double GetYFromX(double x)
        {
            double y = this.a * x + this.b;
            return y;
        }

        /// <summary>
        /// Chceck if the point is on the left side of the line
        /// </summary>
        /// <param name="p"></param>
        /// <returns>True if point is on the left</returns>
        public bool OnLeft(Point p)
        {
            Vector to = new Vector(line_point, p);
            double x;
            if ((x = vec.AngleBetween(to).val) <= Math.PI) return false;
            return true;
        }

        public Line Parallel(double distance, bool on_left = true)
        {
            Vector mov = new Vector(vec);
            if (on_left == true)
            {
                mov.Rotate(new Angle(Math.PI / 2));
            }
            else
            {
                mov.Rotate(new Angle(3 * Math.PI / 2));
            }

            mov.SetLength(distance);
            Line ret = new Line(this);
            ret.line_point.Move(mov);
            return ret;
        }

        /// <summary>
        /// Calculates the a and b parameters from the starting point and the direction vector
        /// </summary>
        private void Calculab()
        {
            a = Math.Tan(vec.angle.val);
            b = line_point.y - line_point.x * a;
        }
    }
}
